package com.fanrui.code.chess.mahjong.round;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.fanrui.code.chess.mahjong.AbstractMahjongTable;
import com.fanrui.code.chess.mahjong.BaoHuRules;
import com.fanrui.code.chess.mahjong.GanZhouMahjongRules;
import com.fanrui.code.chess.mahjong.Mahjong;
import com.fanrui.code.chess.mahjong.MahjongGamer;
import com.fanrui.code.chess.mahjong.MahjongIncome;
import com.fanrui.code.chess.mahjong.MahjongIncome.MahjongIncomeInfo;
import com.fanrui.code.chess.mahjong.MahjongStandings.StandingsOperationType;
import com.fanrui.code.chess.mahjong.StandingsRound;
import com.fanrui.code.mahjong.util.Jing;
import com.fanrui.code.mahjong.util.MahjongCardUtil;
import com.fanrui.code.util.logger.Stdout;
import com.fanrui.proto.cmd.EachHu;
import com.fanrui.proto.cmd.EveryHuType.IconmeType;
import com.fanrui.proto.cmd.HuType;
import com.fanrui.proto.cmd.MaMahjong;
import com.fanrui.proto.cmd.MahjongGroup;
import com.fanrui.proto.cmd.NotifyPlayerHu;
import com.fanrui.proto.cmd.Operation;
import com.fanrui.proto.cmd.ResPlayerOperation.Result;
import com.fanrui.proto.cmd.WannengType;
import com.google.gson.annotations.Expose;

/**
 * @ClassName: MahjongHuRound
 * @Description: 胡牌 是一种特殊的回合不需要玩家响应
 * @author bear
 */
public class MahjongHuRound extends MahjongRound {
	private boolean autoNext = false;
	@Expose
	private MahjongOperationResponse response;
	private MahjongOperationResponse scoure;
	private boolean isQiangGang = false;

	public MahjongHuRound(MahjongOperationResponse scoure, AbstractMahjongTable<?> table,
			MahjongOperationResponse response, boolean autoNext, boolean isQiangGang) {
		super(0, response.getOperationId(), null, table);
		this.autoNext = autoNext;
		this.response = response;
		this.scoure = scoure;
		this.isQiangGang = isQiangGang;
	}

	@Override
	public Result addResponse(MahjongOperationResponse response) {
		return Result.Success;
	}

	@Override
	public Object doResponse() {
		return null;
	}

	@Override
	public void before() {
		boolean zimo = response.getOperationId() == scoure.getOperationId();

		MahjongGamer gamer = table.getGamerByPlayerID(currentId);
		gamer.setHu(true);
		
		gamer.addGroup(Arrays.asList(response.getCard()), response.getType());
		// 如果是自摸 从手牌中移除这张牌
		if (zimo) {
			gamer.removeCard(response.getCard());
		}
		
		if (isQiangGang) {// 如果是被抢杠胡了牌 移除被抢杠人的手牌
			MahjongGamer byQiangGangGamer = table.getGamerByPlayerID(scoure.getOperationId());
			if (byQiangGangGamer != null) {
				byQiangGangGamer.removeCard(scoure.getCard());
			}
			// 发送被抢杠胡的通知
//			NotifyQiangGangHu.Builder qiangGangHuNotify = NotifyQiangGangHu.newBuilder();
//			qiangGangHuNotify.setMj(scoure.getCard().toCardCmd());
//			qiangGangHuNotify.setUserID(scoure.getOperationId());
//			table.broadcast(qiangGangHuNotify.build());
		}
		
		//TODO 不适合放在这里，计算玩家手中的精牌个数
		for (MahjongGamer mg : table.getGamers().values()) {
			if(mg.getHandCards() != null && !mg.getHandCards().isEmpty()) {
				for(Mahjong mj : mg.getHandCards()) {
					if(mj.getWannengType() != null) {
						mg.addJing(mj.getWannengType());
					}
				}
			}
			if(mg.getGroup() != null && !mg.getGroup().isEmpty()) {
				for(MahjongGroup mGroup : mg.getGroup()) {
					for(com.fanrui.proto.cmd.Mahjong mj : mGroup.getMjsList()) {
						if(mj.getWannengType() != null) {
							mg.addJing(mj.getWannengType());
						}
					}
				}
			}
		}
		
		// 通知有人胡牌
		NotifyPlayerHu.Builder notify = NotifyPlayerHu.newBuilder();
		EachHu.Builder eachHu = EachHu.newBuilder();
		eachHu.setUserID(currentId);
		eachHu.setMj(response.getCard().toCardCmd());
		eachHu.setIsBoom(response.getType() == Operation.BOOM);
		String income = MahjongIncome.toJsonString(accounting());
		eachHu.setIncome(income);
		notify.addEHu(eachHu.build());
		// 自摸设置自动摸牌
		if(zimo) {
			if (!table.isHaveHu()) {
				table.setHaveHu(true);
			}
		}
		// 如庄家胡牌，则庄家继续做庄，如闲家胡牌，则现任庄家的下家作为下局的庄家。（赣州）
		if(!currentId.equals(table.getBankID())) {
			table.setBankID(table.getGamerBySeatNO(table.getNextSeatNo(table.getSeatNoByPlayerID(table.getBankID()))).getPlayerID());
		}
		if(table.getGameRules() instanceof BaoHuRules)//开局房主为庄，谁胡牌谁为庄，流局庄家连庄，一炮多响点炮的玩家为庄
			table.setBankID(currentId);
		table.broadcast(notify.build());
		table.setTouchPlayerId(table.getNextExistSeatPlayerId(currentId));
		table.addRound(this);
		if (autoNext) { // 如果是自摸 自动开始下一个人摸牌
			table.startRound(null);
		}
	}

	@Override
	public MahjongOperationResponse getScoreResponse() {
		return null;
	}

	@Override
	public boolean isAoutoNext() {
		return false;
	}

	@Override
	public String toString() {
		return String.format("玩家%s %s", currentId, response.getOperationId() == scoure.getOperationId() ? "自摸" : "胡牌");
	}

	@Override
	public Collection<Long> getCanResponseList() {
		return Collections.emptyList();
	}

	/**
	 * 算账
	 */
	public Collection<MahjongIncome> accounting() {
		MahjongGamer winer = table.getGamerByPlayerID(currentId);
		boolean isZiMo = response.getType() == Operation.ZIMO;
		int baseScore = table.getGameRules().getBaseScore();// 底分
		List<HuType> huTyps = MahjongCardUtil.getInstance().getMult(response.getCard(), winer, isZiMo, table.isGang(), isQiangGang);//牌型
		
		int maNumber = 0; // 中马个数
		if(table.getGameRules() instanceof GanZhouMahjongRules) {//赣州规则
			// 天胡只有庄家才有。起手就和牌（一张没打就和牌了）
			if (table.notTouch() && isZiMo && currentId == table.getBankID().longValue()) {
				huTyps.add(HuType.TIANHU);
			}
			// 自己没有摸牌也没有打牌就算地胡
			if(!table.getBankID().equals(winer.getPlayerID()) && winer.getGroup() != null && winer.getGroup().size() == 1 && winer.notSend()) {
				huTyps.add(HuType.DIHU);
			}
			
			/** 计算精分 **/
			Map<Long, Integer> gamerJingScore = new HashMap<Long, Integer>();
			int allJingFen = 0;
			for(MahjongGamer mg : table.getGamers().values()) {
				int score = 0;
				for(Jing jing : mg.getJings()) {
					int number = jing.getNumber();
					if(jing.getType() == WannengType.ShangZheng || jing.getType() == WannengType.XiaZheng || jing.getType() == WannengType.ZuoZheng || jing.getType() == WannengType.YouZheng ||jing.getType() == WannengType.ZuozuoZheng || jing.getType() == WannengType.YouyouZheng) {
						score += number *= 2;
					}else {
						score += number;
					}
				}
				gamerJingScore.put(mg.getPlayerID(), score);
				allJingFen += score;
			}
			
			if(allJingFen == 0) { //所有人都没有精牌就是德中德
				huTyps.remove(HuType.DEGUO);
				huTyps.add(HuType.DEZHONGDE);
			}
			
			// 霸王/霸王精
			// 一个玩家有精，其他玩家没精，有精的玩家就是霸王。此有精的玩家又冲关，就是霸王精，也要翻倍。
//			int havaJingNumber = 0; // 有精的玩家个数
//			boolean baWang = false;
//			boolean baWangJing = false;
//			for(MahjongGamer mg : table.getGamers().values()) {
//				int jingNumber = 0;
//				int jingTotal = 0;
//				for(Jing jing : mg.getJings()) {
//					jingNumber += jing.getNumber();
//					if(jing.getType() == WannengType.ShangZheng || jing.getType() == WannengType.XiaZheng || jing.getType() == WannengType.ZuoZheng || jing.getType() == WannengType.YouZheng ||jing.getType() == WannengType.ZuozuoZheng || jing.getType() == WannengType.YouyouZheng) {
//						jingTotal += jingNumber *= 2;
//					}else {
//						jingTotal += jingNumber;
//					}
//				}
//				if(jingTotal > 4) {
//					baWangJing = true;
//				}
//				if(jingNumber > 0) {
//					havaJingNumber++;
//				}
//			}
//			if(havaJingNumber == 1) {
//				baWang = true;
//			}
			
			List<Long> gamerIds1 = table.getAllPlayersId();
			List<Long> gamerIds2 = table.getAllPlayersId();
			flag : for (int i = 0; i < gamerIds1.size(); i++) {
				for (int j = i; j < gamerIds2.size(); j++) {
					if(gamerIds1.size() <= i || gamerIds2.size() <= j) {
						Stdout.GET().error("精牌结算：ArrayIndexOutOfBoundsException");
						break flag;
					}
					Long id1 = gamerIds1.get(i);
					Long id2 = gamerIds2.get(j);
					if(id1 == null || id2 == null) {
						Stdout.GET().error("精牌结算：NullPointException(id1 or id2)");
						break flag;
					}
					if(id1.equals(id2)) {
						continue;//自己不用和自己比较
					}
					MahjongGamer gamer = table.getGamerByPlayerID(id1);
					MahjongGamer otherGamer = table.getGamerByPlayerID(id2);
					if(gamer == null || otherGamer == null) {
						Stdout.GET().error("精牌结算：NullPointException(gamer or otherGamer)");
						break flag;
					}
					// 开始计算精分
					List<Jing> jings = gamer.getJings();
					List<Jing> otherJings = otherGamer.getJings();
					if(jings.size() != otherJings.size()) {
						Stdout.GET().error("精牌结算：NullPointException(jing or otherJing)");
						break flag;
					}
					for (int k = 0; k < jings.size(); k++) {
						// 正精2分，副精1分
						Jing jing = jings.get(k), otherJing = otherJings.get(k);
						boolean isZheng = false;
						if(jing.getType() == WannengType.ShangZheng || jing.getType() == WannengType.XiaZheng ||
							jing.getType() == WannengType.ZuoZheng || jing.getType() == WannengType.YouZheng ||
							jing.getType() == WannengType.ZuozuoZheng || jing.getType() == WannengType.YouyouZheng) {
							isZheng = true;
						}
						int base = baseScore * (isZheng ? 2 : 1);
						int jingNumber = jing.getNumber() - otherJing.getNumber();
						jing.addTotal(base*jingNumber);
						otherJing.addTotal(-base*jingNumber);
					}
				}
			}
			
			// 实际玩家金额加减
			for(MahjongGamer mg : table.getGamers().values()) {
				System.out.println("=====================================================");
				System.out.println("玩家：【"+mg.getGamerID()+"】");
				int total = 0;
				for(Jing jing : mg.getJings()) {
					total += jing.getTotal();
					System.out.println("          "+jing.getType()+"=======>>"+jing.getNumber()+"个"+"=======>>"+jing.getTotal()+"分");
				}
				System.out.println("玩家：【"+mg.getGamerID()+"】，或得精分："+total);
				MahjongIncome mi = new MahjongIncome(mg.getPlayerID(), total, IconmeType.JingFen, null);
				mg.addIncomeBuyOne(mi);
				System.out.println("=====================================================");
			}
		}else {//爆胡规则
			// 计算马牌  159  26  37  48
			int seatNo = winer.getSeatNo();
			List<Integer> list = new ArrayList<Integer>();
			int maxNumber = table.getGameRules().getRoomConfig().getPlayerNumber();
			if(maxNumber == 4) {
				if(seatNo == 0) {//东
					list.add(1);
					list.add(5);
					list.add(9);
				}else if(seatNo == 1) {//南
					list.add(2);
					list.add(6);
				}else if(seatNo == 2) {//西
					list.add(3);
					list.add(7);
				}else if(seatNo == 3) {//北
					list.add(4);
					list.add(8);
				}
			}else if(maxNumber == 3) {
				if(seatNo == 0) {//东
					list.add(1);
					list.add(4);
					list.add(7);
				}else if(seatNo == 1) {//南
					list.add(2);
					list.add(5);
					list.add(8);
				}else if(seatNo == 2) {//西
					list.add(3);
					list.add(6);
					list.add(9);
				}
			}else if(maxNumber == 2) {
				if(seatNo == 0) {//东
					list.add(1);
					list.add(3);
					list.add(5);
					list.add(7);
					list.add(9);
				}else if(seatNo == 1) {//南
					list.add(2);
					list.add(4);
					list.add(6);
					list.add(8);
				}
			}
			for(MaMahjong.Builder mm : table.getMaMahjongs()) {
				for(Integer i : list) {
					if(mm.getMj().getNumber() == i) {
						maNumber++;
						mm.setIsWinning(true);
					}
				}
			}
		}
		// 要扣的金额 = 低分*翻数
		int mult = table.getGameRules().convertMulAndRemoveType(huTyps); // 番数
		mult += maNumber;
		baseScore *= mult;
		if(table.getGameRules().getRoomConfig().getGanZhouPlayStyle().getQiangGangHuDouble() && huTyps.contains(HuType.QIANGGANG)) {//抢杠翻倍
			baseScore *= 2;
		}
		
		// 庄闲翻倍
		if(table.getGameRules().getRoomConfig().getBanker()) {
			if(table.getBankID().equals(winer.getPlayerID())) {
				baseScore *= 2;
			}
		}
		
		int total = 0;
		ArrayList<MahjongIncome> list = new ArrayList<MahjongIncome>();
		ArrayList<MahjongIncomeInfo> incomeInfo = new ArrayList<MahjongIncomeInfo>();
		Collection<Long> players;
		
		if(isZiMo) {//自摸
			players = table.getSurvivalPlayers(currentId);
			for (long id : players) {
				boolean isBank = false;
				if(table.getGameRules().getRoomConfig().getBanker()) {
					if(table.getBankID().equals(id)) {
						baseScore *= 2;
						isBank = true;
					}
				}
				MahjongGamer gamer = table.getGamerByPlayerID(id);
				baseScore = gamer.getRealMoney(baseScore);
				MahjongIncome mi = new MahjongIncome(id, -baseScore, IconmeType.ZiMo, huTyps,
						MahjongIncomeInfo.build(currentId, baseScore));
				list.add(mi);
				incomeInfo.add(MahjongIncomeInfo.build(id, baseScore));
				gamer.addIncome(mi);
				total += baseScore;
				if(isBank) {
					baseScore /= 2;
				}
			}
		}else {//点炮
			players = new ArrayList<>();
			MahjongGamer scoureGamer = table.getGamerByPlayerID(scoure.getOperationId());
			if(table.getGameRules().getRoomConfig().getBanker()) {
				if(table.getBankID().equals(scoureGamer.getPlayerID())) {
					baseScore *= 2;
				}
			}
			baseScore = scoureGamer.getRealMoney(baseScore);
			baseScore = winer.getRealMoney(baseScore);
			MahjongIncome mi = new MahjongIncome(scoureGamer.getPlayerID(), -baseScore, IconmeType.FangPao, huTyps,
					MahjongIncomeInfo.build(currentId, baseScore));
			list.add(mi);
			scoureGamer.addIncome(mi);
			incomeInfo.add(MahjongIncomeInfo.build(scoureGamer.getPlayerID(), baseScore));
			total += baseScore;
			players.add(scoureGamer.getPlayerID());
		}
		total = winer.getRealMoney(total);
		MahjongIncome win = new MahjongIncome(currentId, total,
				response.getType() != Operation.ZIMO ? IconmeType.FangPao : IconmeType.ZiMo, huTyps, incomeInfo);
		winer.addIncome(win);
		list.add(win);
		return list;
	}

	@Override
	public StandingsRound toStandingsRound() {
		if(response.getType() ==  Operation.ZIMO){
			return new StandingsRound(StandingsOperationType.ZiMo, currentId, null, response.getCard());
		}
		return new StandingsRound(StandingsOperationType.Hu, currentId, null, response.getCard());
	}

	@Override
	public String getInfo() {
		return String.format("牌桌ID:%s --- 玩家:%s 胡牌回合", table.getID(), currentId);
	}
}
